package com.candoit.webapps.pricing.controllers;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;

import com.candoit.webapps.pricing.model.Articulo;
import com.candoit.webapps.pricing.model.Categoria;
import com.candoit.webapps.pricing.model.CentroCostos;
import com.candoit.webapps.pricing.model.CentroCostosCriterio;
import com.candoit.webapps.pricing.model.ConsumoPapelMes;
import com.candoit.webapps.pricing.model.CriterioDistribucion;
import com.candoit.webapps.pricing.model.Cuenta;
import com.candoit.webapps.pricing.model.CuentaMes;
import com.candoit.webapps.pricing.model.Linea;
import com.candoit.webapps.pricing.model.Maquina;
import com.candoit.webapps.pricing.model.MateriaPrima;
import com.candoit.webapps.pricing.model.MateriaPrimaArticulo;
import com.candoit.webapps.pricing.model.Moneda;
import com.candoit.webapps.pricing.model.OrdenTrabajo;
import com.candoit.webapps.pricing.model.TipoMateriaPrima;
import com.candoit.webapps.pricing.util.AperturaCostoMateriaPrimaUtil;
import com.candoit.webapps.pricing.util.AperturaCostos;
import com.candoit.webapps.pricing.util.CostoRealUtil;
import com.candoit.webapps.pricing.util.CostoSalariosUtil;
import com.candoit.webapps.pricing.util.QueryUtil;


public class CostosMateriasPrimasController extends AbstractController {
	
	private List<Articulo> articulos = null;
	
	private List<AperturaCostoMateriaPrimaUtil> utilAll= null; 
	
	private Linea lineaSelected = null; 
	
	private MateriaPrima materiaPrimaSelected = null;
	
	private Articulo articuloSelected = null;
	
	private boolean selectProduct = false;
	
	private List<Articulo> articulosDetail = null;
	
	private Map<Integer, Double> mapDistribucion = null;
	
	private Double costoIndirecto = 0.00;
	
	private Double costoIndirectoSim = 0.00;

	private Double salarioIndirecto = 0.00;
	
	private Double salarioIndirectoSim = 0.00;
	
	private Moneda moneda =null;
	
	private List<Linea> listaLineas;
	
	private Map<Articulo, List<CostoRealUtil>> mapaArticulos = null;
	
	private Map<CriterioDistribucion, Map<CentroCostos,Double>> matriz_proporcion_criterio_cc = null;
	
	private List<Linea> lineasSeleccionadas = null;
	
	private List<MateriaPrima> papeles = null;

	private Double nivelProductivo = 2550000.0;
	
	private Double gastoImpresion = 0.0d;
	private Double gastoConfeccion = 0.0d;
	private Double gastoEmpaquetado = 0.0d;
	
	private Double salarioImpresion = 0.0d;
	private Double salarioConfeccion = 0.0d;
	private Double salarioEmpaquetado = 0.0d;
	
	private Double gastoImpresionSim = 0.0d;
	private Double gastoConfeccionSim = 0.0d;
	private Double gastoEmpaquetadoSim = 0.0d;
	
	private Double salarioImpresionSim = 0.0d;
	private Double salarioConfeccionSim = 0.0d;
	private Double salarioEmpaquetadoSim = 0.0d;
	
	
	public CostosMateriasPrimasController(){
		moneda = QueryUtil.getInstance().getCotizacionMoneda();
		init_matriz_proporcion_criterio_cc();
		initGastoDirecto();
		initGastoIndirecto();
		initSalarioDirecto();
		initSalarioIndirecto();
		getArticulos();
		mapaArticulos = new HashMap<Articulo, List<CostoRealUtil>>();
		for (Articulo a :articulos){
			List<CostoRealUtil> auxList = listResumeCostos(a);
			mapaArticulos.put(a, auxList);
		}
	}
	
	private Double getProporcion(CriterioDistribucion c, CentroCostos cc){
		Double proporcion = 0.0d;
		try {
			proporcion = matriz_proporcion_criterio_cc.get(c).get(cc);
		} catch (Exception e) {
//			System.out.println(c.toString() + cc.toString());
		}
		return proporcion;
	}
	
	private void init_matriz_proporcion_criterio_cc(){
		List<CriterioDistribucion> criterios = QueryUtil.getInstance().getCriterios();
		List<CentroCostos> ccs = QueryUtil.getInstance().getCentroCostos();
		
		matriz_proporcion_criterio_cc = new HashMap<CriterioDistribucion, Map<CentroCostos,Double>>();
		
		for (CriterioDistribucion c : criterios){
			matriz_proporcion_criterio_cc.put(c,new HashMap<CentroCostos, Double>());
			
			Double sumaProporciones = 0.0d;
			/*Guardo las proporciones no porcentuales en la matriz*/
			for (CentroCostos cc : ccs){
				CentroCostosCriterio ccc = QueryUtil.getInstance().getCentroCostosCriterioObject(cc, c);
				Double propocionNoPorcentual = (ccc == null)? 0.0d : ccc.getCantidad();
				matriz_proporcion_criterio_cc.get(c).put(cc, propocionNoPorcentual);
				sumaProporciones += propocionNoPorcentual;
			}
			
			/*Ahora que conozco el total cargo la proporciones porcentuales en la matriz*/
			for (CentroCostos cc : ccs){
				Double propocionPorcentual = matriz_proporcion_criterio_cc.get(c).get(cc) / sumaProporciones;
				matriz_proporcion_criterio_cc.get(c).put(cc, propocionPorcentual);
			}
		}
	}
	
	public List<CostoRealUtil> summaryCostList(Articulo articulo){
		return mapaArticulos.get(articulo);
	}
	
	public List<Articulo> getArticulos() {
		if (articulos == null){
			if (lineasSeleccionadas == null || lineasSeleccionadas.isEmpty()){
				articulos = QueryUtil.getInstance().getArticulos();
			}else{
				articulos = QueryUtil.getInstance().getArticulosByLineas(lineasSeleccionadas);
			}
		}
		
		return articulos;
	}

	public void setArticulos(List<Articulo> articulos) {
		this.articulos = articulos;
	}
	
	public List<AperturaCostoMateriaPrimaUtil> listMateriaPrimas(Articulo articulo){
		if (articulo != null){
			List<TipoMateriaPrima> tipos = QueryUtil.getInstance().getTipoMateriaPrimaExceptsMO();
			List<AperturaCostoMateriaPrimaUtil> result = new ArrayList<AperturaCostoMateriaPrimaUtil>();
			if (papeles == null || papeles.isEmpty()){
				papeles = QueryUtil.getInstance().getMateriaPrimaByPapel();
			}
				Iterator<MateriaPrima> it = papeles.iterator();
				while (it.hasNext()){
					MateriaPrima mat =(MateriaPrima) it.next();
					AperturaCostoMateriaPrimaUtil util = new AperturaCostoMateriaPrimaUtil();
					util.setArticulo(articulo);
					util.setMateriaPrima(mat);
					for(TipoMateriaPrima tipo : tipos){
						MateriaPrimaArticulo consumo = QueryUtil.getInstance().getMateriaPrimaArticulo(articulo, tipo);
							if (consumo != null){
								this.llenarConsumos(util, consumo, tipo);
							}
						}
				Double scrap = util.getCostoMp() * 0.10;
				Double costoMp = util.getCostoMp();
				util.setCostoMp(costoMp + scrap);	
				result.add(util);
				}
			
			return result;
		}else{
			return null;
		}
	}

	public List<AperturaCostos> listCostos(Articulo articulo){
		if (articulo != null){
			List<AperturaCostos> result = new ArrayList<AperturaCostos>();
			DecimalFormat fourDForm = new DecimalFormat("#.####");
			Iterator<MateriaPrima> it  = null;
			if (papeles == null || papeles.isEmpty()){
				List<MateriaPrima> list = QueryUtil.getInstance().getMateriaPrimaByPapel();
				it = list.iterator();
			}else{
				it = papeles.iterator();
			}
				while (it.hasNext()){
					MateriaPrima materia = (MateriaPrima) it.next();
					AperturaCostos apertura = new AperturaCostos();
					apertura.setMateria(materia);
					apertura.setArticulo(articulo); 
					Double costoMp = calcularCostoMPArticuloDolar(articulo, materia,false);
					Double scrap = costoMp * 0.10d;
					costoMp = costoMp + scrap;
					Double costoSalarios = getCostoSalariosDolar(articulo,false);
					
					apertura.setCostoDetalle(getCostoDirectoDolar(articulo, false)+getCostoIndirectoDolar(false));
					apertura.setCostoTotal(costoMp + apertura.getCostoDetalle() + costoSalarios);
					
					DecimalFormat faux = new DecimalFormat("#.##");
					apertura.setCostoMp(moneda.getSimbolo() +" "+fourDForm.format(costoMp)+" ("+ faux.format(costoMp*100/apertura.getCostoTotal()) +"%)");
					apertura.setSueldos(moneda.getSimbolo()+" "+ fourDForm.format(costoSalarios)+" ("+ faux.format(costoSalarios*100/apertura.getCostoTotal()) +"%)");
					apertura.setCostoDetalleMsg(moneda.getSimbolo()+" "+fourDForm.format(apertura.getCostoDetalle())+" ("+ faux.format(apertura.getCostoDetalle()*100/apertura.getCostoTotal()) +"%)");
					
					result.add(apertura);
				}
			
			return result;
		
		}else{
			return null;
		}
	}	
	
	private Double calcularCostoMPArticulo(Articulo articulo, MateriaPrima materia, boolean simulado){
		Double costo = 0.0;
		
		List<TipoMateriaPrima> tipos = QueryUtil.getInstance().getTipoMateriaPrimaExceptsMO();
		for (TipoMateriaPrima tipo : tipos){
			MateriaPrimaArticulo consumo = QueryUtil.getInstance().getMateriaPrimaArticulo(articulo, tipo);
			Double cUnit = 0.0;
			if (consumo != null){	
				if (materia.getGramaje() != null && tipo.getId() == TipoMateriaPrima.PAPEL ){
					cUnit = costoPapel(materia,simulado)*materia.getGramaje();
				}else if( tipo.getId() == TipoMateriaPrima.MODULO ){
					cUnit = costoPapel(materia,simulado);
				}else{
					cUnit = costoUnitarioNoPapel(tipo,simulado);
				}
				if (consumo.getConsummo() != null){
					costo += consumo.getConsummo() * cUnit;
				}
			}
		}
		
		return costo;
	}
	
	
	private Double calcularCostoMPArticuloDolar(Articulo articulo, MateriaPrima materia, boolean simulado){
		return calcularCostoMPArticulo(articulo, materia, simulado)/moneda.getCotizacion();
	}
	
	private Double costoPapel(MateriaPrima materia, boolean simulado){
		Double costoUnitario = 0.0;
		if (!simulado){	
			costoUnitario = materia.getCostoUnitario();
		}else{
			if (materia.getCostoSimulado()!= null){
				costoUnitario = materia.getCostoSimulado();
			}else{
				costoUnitario = materia.getCostoUnitario();
			}
		}
		return costoUnitario;
	}
		
	private Double costoUnitarioNoPapel(TipoMateriaPrima tipo, boolean simulado){
		Double costoUnitario = 0.0;
		MateriaPrima mp = QueryUtil.getInstance().getMateriaPrimaByTipoMateria(tipo).get(0);
		mp.setCostoUnitario( (mp.getCostoUnitario() != null)? mp.getCostoUnitario() : 0.0 );
		if (!simulado){	
			costoUnitario = mp.getCostoUnitario();
		}else{
			if (mp.getCostoSimulado()!= null && mp.getCostoSimulado() != 0.0){
				costoUnitario = mp.getCostoSimulado();
			}else{
				costoUnitario = mp.getCostoUnitario();
			}
		}
		return costoUnitario;
	}
	
//	private Map<String,Double> getCostoMpArticulo(Articulo articulo, MateriaPrima materia, boolean simulado){
//		Map<String,Double> map = new HashMap<String, Double>();
//		List<TipoMateriaPrima> tipos = QueryUtil.getInstance().getTipoMateriaPrimaExceptsMO();
//		for (TipoMateriaPrima tipo : tipos){
//			MateriaPrimaArticulo consumo = QueryUtil.getInstance().getMateriaPrimaArticulo(articulo, tipo);
//			if (consumo != null){	
//				Double consumoResult = 0.00d;
//				Double costoUnitarioDolares = 0.00d;
//				if (!simulado){	
//					costoUnitarioDolares = materia.getCostoUnitario() / moneda.getCotizacion();
//				}else{
//					if (materia.getCostoSimulado()!= null){
//						costoUnitarioDolares = materia.getCostoSimulado() / moneda.getCotizacion();
//					}else{
//						costoUnitarioDolares = materia.getCostoUnitario() / moneda.getCotizacion();
//					}
//				}
//				if (materia.getGramaje() != null && tipo.getId() == TipoMateriaPrima.PAPEL ){
//					Double consumoAux = consumo.getConsummo() * costoUnitarioDolares;
//					consumoResult = consumoAux * materia.getGramaje();
//					if (!map.containsKey("total")){
//						map.put("total", consumoResult);
//					}else{
//						map.put("total", map.get("total") + consumoResult);
//					}
//					if (!map.containsKey("scrap")){
//						map.put("scrap", consumoResult);
//					}else{
//						map.put("scrap", map.get("scrap") + consumoResult);
//					}
//				}else{
//					consumoResult = consumo.getConsummo() * costoUnitarioDolares;
//					if (!map.containsKey("total")){
//						map.put("total", consumoResult);
//					}else{
//						map.put("total", map.get("total") + consumoResult);
//					}
//					if (!map.containsKey("scrap")){
//						map.put("scrap", consumoResult);
//					}else{
//						map.put("scrap", map.get("scrap") + consumoResult);
//					}
//				}
//			   }
//		}
//		
//		return map;
//	}
	
	private Double getCostoSalarios(Articulo articulo, boolean simulado){
		Double costo;
		if (!simulado){
			costo = getSalarioDirecto(articulo, simulado) + this.salarioIndirecto;
		}else{
			costo = getSalarioDirecto(articulo, simulado) + this.salarioIndirectoSim;
		}
		
		return costo;
	}

	private Double getCostoSalariosDolar(Articulo articulo, boolean simulado){
		Double salarioPesos = getCostoSalarios(articulo,simulado);
		Double salarioDolares = salarioPesos/moneda.getCotizacion();
		return salarioDolares;
	}
	
	public List<AperturaCostoMateriaPrimaUtil> getUtilAll() {
		return utilAll;
	}

	public void setUtilAll(List<AperturaCostoMateriaPrimaUtil> utilAll) {
		this.utilAll = utilAll;
	}

	public Linea getLineaSelected() {
		return lineaSelected;
	}

	public void setLineaSelected(Linea lineaSelected) {
		this.lineaSelected = lineaSelected;
	}
	
	public void buscarArticulos(){
		if (lineasSeleccionadas == null || lineasSeleccionadas.isEmpty()){
			articulos = QueryUtil.getInstance().getArticulos();
		}else{
			articulos = QueryUtil.getInstance().getArticulosByLineas(lineasSeleccionadas);
		}
		for(Articulo a : articulos){
		List<CostoRealUtil> auxList = listResumeCostos(a);
		mapaArticulos.put(a, auxList);
		}
	}
	
	public List<CostoRealUtil> listResumeCostos(Articulo articulo){
		if (articulo != null){
			List<CostoRealUtil> result = new ArrayList<CostoRealUtil>();
			Iterator<MateriaPrima> it  = null;
			if (papeles == null || papeles.isEmpty()){
				List<MateriaPrima> list = QueryUtil.getInstance().getMateriaPrimaByPapelActivos();
				it = list.iterator();
			}else{
				it = papeles.iterator();
			}
				while (it.hasNext()){
					MateriaPrima materia = (MateriaPrima) it.next();
					prepareCommandCost(result,articulo,materia);
				}
			
			return result;
		
		}else{
			return null;
		}
	}
	
	private void prepareCommandCost(List<CostoRealUtil> result, Articulo articulo, MateriaPrima materia){
		DecimalFormat fourDForm = new DecimalFormat("#.####");
		CostoRealUtil util = new CostoRealUtil();
		util.setMateria(materia);

		Double costoMp = calcularCostoMPArticuloDolar(articulo, materia,false);
		Double scrap = costoMp * 0.10d;
		costoMp = costoMp + scrap;
		Double costoDirecto = getCostoDirectoDolar(articulo, false);
		Double costoIndirecto = getCostoIndirectoDolar(false);
		Double costoSalario = getCostoSalariosDolar(articulo,false);
		Double costoReal= costoMp + costoDirecto + costoIndirecto + costoSalario;
		Double rentabilidad = 0.00d;
		if (articulo.getFormato() != null){
			rentabilidad = articulo.getFormato().getRentabilidad();
		}
		Double precioReal = calcularPrecio(costoReal, rentabilidad);
		
		util.setPorcentajeReal( precioReal);
		util.setCostoReal(fourDForm.format(costoReal));
		
		Double costoMpSim = calcularCostoMPArticuloDolar(articulo, materia,true);
		Double scrapSim = costoMpSim * 0.10d;
		costoMpSim = costoMpSim + scrapSim;
		Double costoDirectoSim = getCostoDirectoDolar(articulo, true);
		Double costoIndirectoSim = getCostoIndirectoDolar(true);
		Double costoSalarioSim = getCostoSalariosDolar(articulo,true);
		Double costoSim = costoMpSim + costoDirectoSim + costoIndirectoSim + costoSalarioSim;
		Double precioSim = calcularPrecio(costoSim, rentabilidad);
		
		util.setCostoSimulado(costoSim);
		util.setPorcentajeSimulado(precioSim);
		
		result.add(util);
	}
	
	 public void grabarRentabilidad(){
         for (Linea linea :listaLineas){
                 this.update(linea);
         }    
	 }
	
	private Double calcularPrecio(Double costo, Double rentabilidad){
		return costo * (1 + rentabilidad/100);
	}

	public List<Articulo> getArticulosDetail() {
		if (articulosDetail == null){
			if (lineasSeleccionadas == null || lineasSeleccionadas.isEmpty()){
				articulosDetail = QueryUtil.getInstance().getArticulos();
			}else{
				articulosDetail = QueryUtil.getInstance().getArticulosByLineas(lineasSeleccionadas);
			}
		}
		
		return articulosDetail;
	}

	public void setArticulosDetail(List<Articulo> articulosDetail) {
		this.articulosDetail = articulosDetail;
	}

	public MateriaPrima getMateriaPrimaSelected() {
		return materiaPrimaSelected;
	}

	public void setMateriaPrimaSelected(MateriaPrima materiaPrimaSelected) {
		this.materiaPrimaSelected = materiaPrimaSelected;
	}

	public Articulo getArticuloSelected() {
		return articuloSelected;
	}

	public void setArticuloSelected(Articulo articuloSelected) {
		this.articuloSelected = articuloSelected;
	}
	
	public boolean isSelectProduct() {
		return selectProduct;
	}

	public void setSelectProduct(boolean selectProduct) {
		this.selectProduct = selectProduct;
	}
	
	public Map<Integer, Double> getMapDistribucion() {
		return mapDistribucion;
	}

	public void setMapDistribucion(Map<Integer, Double> mapDistribucion) {
		this.mapDistribucion = mapDistribucion;
	}
	
	public Double getCostoIndirecto() {
		return costoIndirecto;
	}

	public Double getCostoIndirectoDolar(boolean simulado){
		Double costo;
		if (!simulado){
			costo = getCostoIndirecto()/moneda.getCotizacion();
		}else{
			costo = getCostoIndirectoSim()/moneda.getCotizacion();
		}
		return costo;
	}
	
	public void setCostoIndirecto(Double costoIndirecto) {
		this.costoIndirecto = costoIndirecto;
	}
	
	public Double getCostoIndirectoSim() {
		return costoIndirectoSim;
	}

	public void setCostoIndirectoSim(Double costoIndirectoSim) {
		this.costoIndirectoSim = costoIndirectoSim;
	}

	private void llenarConsumos(AperturaCostoMateriaPrimaUtil util, MateriaPrimaArticulo consumo,TipoMateriaPrima tipo){
		if (tipo.getId() == 1){
			util.setConsumoPapel(consumo.getConsummo());
			Double aux = (util.getMateriaPrima().getCostoUnitario() / moneda.getCotizacion());
			Double costoUnitarioDolares = aux;
			Double costoGramaje = costoUnitarioDolares * util.getMateriaPrima().getGramaje();
			util.setCostoMp(util.getCostoMp() + (consumo.getConsummo() * costoGramaje));
			util.setCostoPapel(costoUnitarioDolares);
		}
		if (tipo.getId() == 2){
			Double costoUnitarioDolares = util.getMateriaPrima().getCostoUnitario() / moneda.getCotizacion();
			util.setConsumoModulo(consumo.getConsummo());
			util.setCostoMp(util.getCostoMp() + (consumo.getConsummo() * costoUnitarioDolares));
			util.setCostoModulo(costoUnitarioDolares);
		}
		if (tipo.getId() == 3){
			Double costoUnitarioDolares = getCostoTipoMateriaPrima(tipo);
			util.setConsumoManija(consumo.getConsummo());
			util.setCostoMp(util.getCostoMp() + (consumo.getConsummo() * costoUnitarioDolares));
			util.setCostoManija(costoUnitarioDolares);
		}
		if (tipo.getId() == 4){
			Double costoUnitarioDolares = getCostoTipoMateriaPrima(tipo);
			util.setConsumoTinta(consumo.getConsummo());
			util.setCostoMp(util.getCostoMp() + (consumo.getConsummo() * costoUnitarioDolares));
			util.setCostoTinta(costoUnitarioDolares);
		}
		if (tipo.getId() == 5){
			Double costoUnitarioDolares = getCostoTipoMateriaPrima(tipo);
			util.setConsumoAdhesivo(consumo.getConsummo());
			util.setCostoMp(util.getCostoMp() + (consumo.getConsummo() * costoUnitarioDolares));
			util.setCostoAdhesivo(costoUnitarioDolares);
		}
		if (tipo.getId() == 6){
			Double costoUnitarioDolares = getCostoTipoMateriaPrima(tipo);
			util.setConsumoHotMel(consumo.getConsummo());
			util.setCostoMp(util.getCostoMp() + (consumo.getConsummo() * costoUnitarioDolares));
			util.setCostoHotMel(costoUnitarioDolares);
		}
		if (tipo.getId() == 7){
			Double costoUnitarioDolares = getCostoTipoMateriaPrima(tipo);
			util.setConsumoEngrudo(consumo.getConsummo());
			util.setCostoMp(util.getCostoMp() + (consumo.getConsummo() * costoUnitarioDolares));
			util.setCostoEngrudo(costoUnitarioDolares);
		}
		
	}
	
	public List<CostoSalariosUtil> listCostosSalarios(Articulo articulo){
		if (articulo != null){
			List<CentroCostos> centros = QueryUtil.getInstance().getCentrosUtecoNewLong();
			List<TipoMateriaPrima> tipos = QueryUtil.getInstance().getTipoMateriaPrimaManoDeObra();
			Iterator<CentroCostos> it = centros.iterator();
			List<CostoSalariosUtil> result = new ArrayList<CostoSalariosUtil>();
			CostoSalariosUtil util = new CostoSalariosUtil();
			while (it.hasNext()){
				   CentroCostos centro = (CentroCostos) it.next();
					Double costoMes = QueryUtil.getInstance().getCostoMesManoDeObra(centro);
					Maquina maquina = QueryUtil.getInstance().getMaquinaByCentroCostos(centro);
					Double costoPorMaquina = costoMes / maquina.getCantidad();
					Double costoPorHora = costoPorMaquina / maquina.getHorasMes();
					Double unidadesPorHora = maquina.getProduccionMensual() / maquina.getHorasMes();
					Double costoPorUnidad = costoPorHora / unidadesPorHora;
					util.setArticulo(articulo);
					util.setMateria(materiaPrimaSelected);
					if (centro.getId() == CentroCostos.NEWLONG_CODE){
						util.setCostoNewLong(costoPorUnidad);
					}
					if (centro.getId() == CentroCostos.UTECO_CODE){
						util.setCostoUteco(costoPorUnidad);
					}
				   for(TipoMateriaPrima tipo : tipos){
					   MateriaPrimaArticulo consumo = QueryUtil.getInstance().getMateriaPrimaArticulo(articulo, tipo);
					   if (centro.getId() == CentroCostos.NEWLONG_CODE && tipo.getId() == TipoMateriaPrima.MO_CONFECCION){
						   util.setConsumoNewLong(consumo.getConsummo());
					   }
					   if (centro.getId() == CentroCostos.UTECO_CODE && tipo.getId() == TipoMateriaPrima.MO_IMPRESION){
							util.setConsumoUteco(consumo.getConsummo());
					   }
					}
				   
				}
				util.setCostoTotal(util.getCostoTotal() + (util.getConsumoNewLong() * util.getCostoNewLong()) + (util.getConsumoUteco()* util.getCostoUteco()));
				result.add(util);
			return result;
		
		}else{
			return null;
		}
	}	
	
//	private Double getCostoDetalle(){
//		Double costo = 0.00d;
//		Calendar cal = new GregorianCalendar();
//		Date fechaActual = new Date();
//		cal.setTime(fechaActual);
//		Integer mesActual = cal.get(Calendar.MONTH);
//		List<CuentaMes> cuentas = QueryUtil.getInstance().getCuentasByMes(mesActual);
//		List<CentroCostos> centros = QueryUtil.getInstance().getCentroCostos();
//		mapDistribucion = new HashMap<Integer, Double>();
//		for(CuentaMes cuenta : cuentas){	
//			for (CentroCostos centro : centros){
//				if (cuenta.getCuentaMesFK().getCuenta().getCriterio() != null ){
//				if (cuenta.getCuentaMesFK().getCuenta().getCriterio().getId() == CriterioDistribucion.DIRECTA_CODE ){
//					if (cuenta.getCuentaMesFK().getCuenta().getCentro().getId() == centro.getId() ){	
//						if (mapDistribucion.containsKey(centro.getId())){
//							mapDistribucion.put(centro.getId(), mapDistribucion.get(centro.getId()) + cuenta.getCosto());	
//						}else{
//							mapDistribucion.put(centro.getId(), cuenta.getCosto());
//						}
//					}	
//				}else{
//					CentroCostosCriterio centroCriterio = QueryUtil.getInstance().getCentroCostosCriterioObject(centro, cuenta.getCuentaMesFK().getCuenta().getCriterio());
//					if (centroCriterio != null){	
//						Double totalCriterio = QueryUtil.getInstance().getTotalAsignadoCriterio(centroCriterio.getFk().getCriterio());
//						Double criterioPorc = centroCriterio.getCantidad()/totalCriterio;
//						Double criterio = cuenta.getCosto() *criterioPorc;
//						if (mapDistribucion.containsKey(centro.getId())){
//							mapDistribucion.put(centro.getId(), mapDistribucion.get(centro.getId()) + criterio);	
//						}else{
//							mapDistribucion.put(centro.getId(), criterio);
//						}
//					}	
//				}
//			 }
//			}	
//		  }	
//		
//		double ind = 0;
//		double total = 0;
//		List<OrdenTrabajoMes> ots = QueryUtil.getInstance().getOrdenesTrabajoMes(mesActual);
//		for (OrdenTrabajoMes ot : ots){
//			 if (ot.getFk().getOrden().getId() == 1){
//				 ind = ot.getCantidad();
//			 }
//			 total = total + ot.getCantidad();
//		}
//		
//		double mix = 0.00d;
//		List<ConsumoPapelMes> consumos = QueryUtil.getInstance().getConsumoPapelMes(mesActual);
//		for(ConsumoPapelMes cons : consumos){
//			if (cons.getFk().getOrden().getId() ==1){
//				mix = cons.getMixConsumoPapel();
//			}
//		}
//		
//		double perc = ind / total;
//		double totalOT = 0.00d;
//		double totalExpedicion = 0.00d;
//		List<CentroCostos> sinAsignar = QueryUtil.getInstance().getCentroCostosByCategoria(Categoria.SIN_ASIGNAR_CODE);
//		for (CentroCostos centro : sinAsignar){
//			 if (!centro.getNombre().equals("EXPEDICION") && mapDistribucion.containsKey(centro.getId())){
//				 if (mapDistribucion.containsKey(centro.getId())){	
//				 	totalOT = totalOT + mapDistribucion.get(centro.getId());
//				 }
//			 }else{
//				 if (centro.getNombre().equals("EXPEDICION")){
//					 if (mapDistribucion.containsKey(centro.getId())){
//						 totalExpedicion = mapDistribucion.get(centro.getId());
//					 }
//				 }
//			 }
//		}
//		
//		double mixperc = mix * perc;
//		if (totalExpedicion > 0.0000d){
//			costo = costo + (totalExpedicion * mixperc);
//		}
//		
//		costo = totalOT * perc;
//		
//		Maquina maquina = QueryUtil.getInstance().getMaquinaByName("NEWLONG");
//		
//		costo = costo / maquina.getCantidad();
//		
//		costo = costo / maquina.getProduccionMensual();
//		
//		return costo;		
//				
//	}
	
	private Double getCostoDirecto(Articulo articulo, boolean simulado){
		
		Double consumoUteco = calcularConsumoMaquina(TipoMateriaPrima.MO_IMPRESION, articulo);
		Double consumoConfeccion = calcularConsumoMaquina(TipoMateriaPrima.MO_CONFECCION, articulo);
		Double consumoEmpaquetado = calcularConsumoMaquina(TipoMateriaPrima.MO_EMPAQUE, articulo);
		
		Double costo;
		if (!simulado){
			costo = this.gastoImpresion * consumoUteco + this.gastoConfeccion * consumoConfeccion + 
			this.gastoEmpaquetado * consumoEmpaquetado;
		}else{
			costo = this.gastoImpresionSim * consumoUteco + this.gastoConfeccionSim * consumoConfeccion + 
			this.gastoEmpaquetadoSim * consumoEmpaquetado;
		}
		
		return costo;
	}
	
	private Double getCostoDirectoDolar(Articulo articulo, boolean simulado){
		return getCostoDirecto(articulo, simulado)/moneda.getCotizacion();
	}
	
	private Double getSalarioDirecto(Articulo articulo, boolean simulado){
		
		Double consumoUteco = calcularConsumoMaquina(TipoMateriaPrima.MO_IMPRESION, articulo);
		Double consumoConfeccion = calcularConsumoMaquina(TipoMateriaPrima.MO_CONFECCION, articulo);
		Double consumoEmpaquetado = calcularConsumoMaquina(TipoMateriaPrima.MO_EMPAQUE, articulo);
		
		Double costo;
		if (!simulado){
			costo = this.salarioImpresion * consumoUteco + this.salarioConfeccion * consumoConfeccion + 
			this.salarioEmpaquetado * consumoEmpaquetado;
		}else{
			costo = this.salarioImpresionSim * consumoUteco + this.salarioConfeccionSim * consumoConfeccion + 
			this.salarioEmpaquetadoSim * consumoEmpaquetado;			
		}
		
		return costo;
	}

	private Double calcularConsumoMaquina(Integer tipoMateriaPrimeID, Articulo articulo){
		TipoMateriaPrima tmp = QueryUtil.getInstance().getTipoMateriaPrimaById(tipoMateriaPrimeID);
		MateriaPrimaArticulo matPrimaArt = QueryUtil.getInstance().getMateriaPrimaArticulo(articulo, tmp);
		Double consumo = 0.00d;
		if (matPrimaArt != null){
			matPrimaArt.getConsummo();
		}	
		return consumo;
	}
	
	private void initGastoIndirecto(){
		this.costoIndirecto = calcularGastoIndirecto(this.nivelProductivo,false);
		this.costoIndirectoSim = calcularGastoIndirecto(this.nivelProductivo,true);
	}
	
	private void initSalarioIndirecto(){
		this.salarioIndirecto = calcularSalarioIndirecto(this.nivelProductivo,false);
		this.salarioIndirectoSim = calcularSalarioIndirecto(this.nivelProductivo,true);
	}
	
	private Double calcularGastoIndirecto(Double nivelProductivo, boolean simulado){
		Double gastoSinAsignarIndustriales = gastoSinAsignarIndustriales(simulado);
		return calculoInternoIndirecto(nivelProductivo, gastoSinAsignarIndustriales);
	}
	
	private Double calcularSalarioIndirecto(Double nivelProductivo, boolean simulado){
		Double gastoSinAsignarIndustriales = salariosSinAsignarIndustriales(simulado);
		return calculoInternoIndirecto(nivelProductivo, gastoSinAsignarIndustriales);
	}
	
	private Double calculoInternoIndirecto(Double nivelProductivo, Double sinAsignarIndustriales){
		CentroCostos cc = QueryUtil.getInstance().getCentroById(CentroCostos.NEWLONG_CODE);
		Maquina m = QueryUtil.getInstance().getMaquinaByCentroCostos(cc);
		Integer cantidadNewlong = m.getCantidad();
		Double indirecto = (sinAsignarIndustriales/cantidadNewlong)/nivelProductivo; 
		return indirecto;
	}
	
	private Double calcularPorcOTIndustrial(){
		List<OrdenTrabajo> otm = QueryUtil.getInstance().getOrdenesTrabajo();
		Double OTTotal = 0.0;
		Double OTIndustrial = 0.0;
		for (OrdenTrabajo ot : otm){
			if (ot.getId() == OrdenTrabajo.AUTOMATICA_CODE){
				OTIndustrial = new Double(ot.getCantidad());
			}
			OTTotal += ot.getCantidad();
		}
		OTIndustrial = OTIndustrial/OTTotal;
		
		return OTIndustrial;
	}
	
	private Double calcularPorcConsumoPapelIndustrial(){
		List<ConsumoPapelMes> cpm = QueryUtil.getInstance().getConsumoPapelMes();
		Double CTotal = 0.0;
		Double CIndustrial = 0.0;
		for (ConsumoPapelMes cp : cpm){
			if (cp.getOrden().getId() == OrdenTrabajo.AUTOMATICA_CODE){
				CIndustrial = cp.getKilos();
			}
			CTotal += cp.getKilos();
		}
		CIndustrial = CIndustrial/CTotal;
		
		return CIndustrial;
	}
	
	private Double calcularPorcKgIndustriales(){
		ConsumoPapelMes cpm = QueryUtil.getInstance().getConsumoPapelMes(OrdenTrabajo.AUTOMATICA_CODE);
		Double mixConsumoPapel = cpm.getMixConsumoPapel();
		Double mixOrdenesTrabajoEmitidas = cpm.getMixOrdenesTrabajoEmitidas();
		Double porcConsumoPapel = 100 * calcularPorcConsumoPapelIndustrial();
		Double industrialMCP = mixConsumoPapel * porcConsumoPapel;
		Double porcOTI = 100 * calcularPorcOTIndustrial();
		Double industrialMOTE = mixOrdenesTrabajoEmitidas * porcOTI;
		Double porcKGI = (industrialMCP + industrialMOTE)/100;
		return porcKGI;
	}
	
	private Double gastoSinAsignarIndustriales(boolean simulado){
		Map <CentroCostos,Double> costosTotalesCCPPI = costosTotalesCCPPI(simulado);
		return calculoInternoSinAsignar(costosTotalesCCPPI);
	}
	
	private Double salariosSinAsignarIndustriales(boolean simulado){
		List<CentroCostos> ccppi = QueryUtil.getInstance().getCentroCostosByCategoria(Categoria.SIN_ASIGNAR_CODE);
		Map <CentroCostos,Double> salariosTotalesCCPPI = costosTotalesCCPPI(simulado);
		for(CentroCostos cc : ccppi){
			Double totalCuenta = QueryUtil.getInstance().getSalarioByCentroCosto(cc, simulado);
			salariosTotalesCCPPI.put(cc,totalCuenta);
		}
		return calculoInternoSinAsignar(salariosTotalesCCPPI);
	}
	
	private Double calculoInternoSinAsignar(Map <CentroCostos,Double> valoresTotalesCCPPI){
		Double OTIndustrial = calcularPorcOTIndustrial();
		Double KgIndustriales = calcularPorcKgIndustriales();
		Double costoSinExpedicion = 0.0;
		Double costoConExpedicion = 0.0;
		for(CentroCostos cc : valoresTotalesCCPPI.keySet()){
			if (cc.getId() != 29){
				costoSinExpedicion += valoresTotalesCCPPI.get(cc);
			}else{
				costoConExpedicion = valoresTotalesCCPPI.get(cc);
			}
		}
		
		Double gastoSinAsignarIndustriales = 0.0;
		gastoSinAsignarIndustriales = costoSinExpedicion * OTIndustrial + costoConExpedicion * KgIndustriales;
		return gastoSinAsignarIndustriales;
	}
	
	private void initSalarioDirecto(){
		Map <CentroCostos,Double> salariosTotalesCCPPD = salariosTotalesCCPPD(false);
		Map <CentroCostos,Double> salariosTotalesCCPPDSim = salariosTotalesCCPPD(true);
		this.salarioImpresion = salarioTareaMaquina(CentroCostos.UTECO_CODE,salariosTotalesCCPPD, false);
		this.salarioConfeccion = salarioTareaMaquina(CentroCostos.NEWLONG_CODE,salariosTotalesCCPPD, false);
		this.salarioEmpaquetado = salarioTareaMaquina(CentroCostos.EMPAQUETADORA_CODE,salariosTotalesCCPPD, false);
		
		this.salarioImpresionSim = salarioTareaMaquina(CentroCostos.UTECO_CODE,salariosTotalesCCPPDSim, true);
		this.salarioConfeccionSim = salarioTareaMaquina(CentroCostos.NEWLONG_CODE,salariosTotalesCCPPDSim, true);
		this.salarioEmpaquetadoSim = salarioTareaMaquina(CentroCostos.EMPAQUETADORA_CODE,salariosTotalesCCPPDSim, true);
	}
	
	private Map <CentroCostos,Double> salariosTotalesCCPPD(boolean simulado){
		return salariosTotalesCCPP(Categoria.SERVICES_CODE, simulado);
	}
	
	private Map <CentroCostos,Double> salariosTotalesCCPP(Integer categoria, boolean simulado){
		Map <CentroCostos,Double> costosTotalesCCPP = new HashMap<CentroCostos, Double>();
		
		List<CentroCostos> paraProductivos = QueryUtil.getInstance().getCentroCostosByCategoria(categoria); 
		
		/*inicializo el mapa*/
		for(CentroCostos cc : paraProductivos){
			costosTotalesCCPP.put(cc, 0.0d);
		}
		
		for(CentroCostos cc : paraProductivos){
			Double totalCuenta = QueryUtil.getInstance().getSalarioByCentroCosto(cc, simulado);
			costosTotalesCCPP.put(cc,totalCuenta);
		}
		
		return costosTotalesCCPP;
	}
	
	private void initGastoDirecto(){
		/*calculo costoso*/
		Map <CentroCostos,Double> costosTotalesCCPPD = costosTotalesCCPPD(false);
		Map <CentroCostos,Double> costosTotalesCCPPDSim = costosTotalesCCPPD(true);
		this.gastoImpresion =  gastoTareaMaquina(CentroCostos.UTECO_CODE,costosTotalesCCPPD,false);
		this.gastoConfeccion = gastoTareaMaquina(CentroCostos.NEWLONG_CODE,costosTotalesCCPPD,false);
		this.gastoEmpaquetado = gastoTareaMaquina(CentroCostos.EMPAQUETADORA_CODE,costosTotalesCCPPD,false);
		
		this.gastoImpresionSim =  gastoTareaMaquina(CentroCostos.UTECO_CODE,costosTotalesCCPPDSim,true);
		this.gastoConfeccionSim = gastoTareaMaquina(CentroCostos.NEWLONG_CODE,costosTotalesCCPPDSim,true);
		this.gastoEmpaquetadoSim = gastoTareaMaquina(CentroCostos.EMPAQUETADORA_CODE,costosTotalesCCPPDSim,true);
	}
	
	private Double salarioTareaMaquina(Integer maquina,Map <CentroCostos,Double> costosTotalesCCPPD, boolean simulado){
		Double costoMensualMaquina = salarioMensualMaquina(maquina,costosTotalesCCPPD,simulado);
		if (maquina == CentroCostos.UTECO_CODE){
			costoMensualMaquina += salarioMensualMaquina(CentroCostos.CORTE_DE_BOBINA_A_BOBINA_CODE,costosTotalesCCPPD,simulado);
		}
		CentroCostos cc = QueryUtil.getInstance().getCentroById(maquina);
		
		Maquina m = QueryUtil.getInstance().getMaquinaByCentroCostos(cc);
		Integer cantidadMaquinas = m.getCantidad();
		
		Double produccionMensualPromedio = m.getProduccionMensual();
		Integer horasMaquinaMensual = m.getHorasMes();
		Double unidadesMaquinasMensuales = produccionMensualPromedio/horasMaquinaMensual;
		
		return (costoMensualMaquina/cantidadMaquinas)/horasMaquinaMensual/unidadesMaquinasMensuales;
	}
	
	private Double salarioMensualMaquina(Integer maquina, Map <CentroCostos,Double> costosTotalesCCPPD,boolean simulado){		
		CentroCostos cc = QueryUtil.getInstance().getCentroById(maquina);
		Double costoTotalCCPporMaquina = QueryUtil.getInstance().getSalarioByCentroCosto(cc, simulado);
		
		Double costosTotalesCCPPDMaquina = costosTotalesCCPPDMaquina(cc,costosTotalesCCPPD);
		
		Double costoMensualMaquina = costoTotalCCPporMaquina + costosTotalesCCPPDMaquina;
		return costoMensualMaquina;
	}
	
	private Double gastoTareaMaquina(Integer maquina,Map <CentroCostos,Double> costosTotalesCCPPD, boolean simulado){
		Double costoMensualMaquina = costoMensualMaquina(maquina,costosTotalesCCPPD, simulado);
		if( maquina == CentroCostos.UTECO_CODE){
			Double gastoCorteBoB = costoMensualMaquina(CentroCostos.CORTE_DE_BOBINA_A_BOBINA_CODE,costosTotalesCCPPD, simulado);
			costoMensualMaquina += gastoCorteBoB;
		}
		
		CentroCostos cc = QueryUtil.getInstance().getCentroById(maquina);
		
		Maquina m = QueryUtil.getInstance().getMaquinaByCentroCostos(cc);
		Integer cantidadMaquinas = m.getCantidad();
		
		Double produccionMensualPromedio = m.getProduccionMensual();
		Integer horasMaquinaMensual = m.getHorasMes();
		Double unidadesMaquinasMensuales = produccionMensualPromedio/horasMaquinaMensual;
		
		return (costoMensualMaquina/cantidadMaquinas)/horasMaquinaMensual/unidadesMaquinasMensuales;
	}
	
	private Double costoMensualMaquina(Integer maquina, Map <CentroCostos,Double> costosTotalesCCPPD, boolean simulado){		
		CentroCostos cc = QueryUtil.getInstance().getCentroById(maquina);
		Double costoTotalCCPporMaquina = costoTotalCCPporMaquina(maquina, simulado);
		
		Double costosTotalesCCPPDMaquina = costosTotalesCCPPDMaquina(cc,costosTotalesCCPPD);
		
		Double costoMensualMaquina = costoTotalCCPporMaquina + costosTotalesCCPPDMaquina;
		return costoMensualMaquina;
	}
	
	/*No requiere simulacion porque los datos del mapa ya pasaron por ese criterio*/
	private Double costosTotalesCCPPDMaquina(CentroCostos maquina, Map <CentroCostos,Double> costosTotalesCCPPD){		
		Double costoTotal = 0.0d;
		
		for (CentroCostos cc : costosTotalesCCPPD.keySet()){
			Double totalCuenta = costosTotalesCCPPD.get(cc);
			CriterioDistribucion c = cc.getCriterio();
			
			Double proporcion = getProporcion(c, maquina);
			costoTotal += totalCuenta*proporcion;
		}
		return costoTotal;
	}
	
	private Double costoTotalCCPporMaquina(Integer maquina, boolean simulado){
		CentroCostos cc = QueryUtil.getInstance().getCentroById(maquina);
		List<Cuenta> cuentas = QueryUtil.getInstance().getCuentas();
		
		Double costoTotal = 0.0d;
		
		for (Cuenta cu : cuentas){
			CuentaMes cum = QueryUtil.getInstance().getUltimaCuenta(cu);
			Double totalCuenta  =0.00d;
			if (cum != null){
				totalCuenta = simulado? cum.getCostoSimulado() : cum.getCosto();
			}
			CriterioDistribucion c = cu.getCriterio();
			
			Double proporcion = getProporcion(c, cc);
			costoTotal += totalCuenta*proporcion;
		}
		return costoTotal;
	}
		
	private Map <CentroCostos,Double> costosTotalesCCPPD(boolean simulado){
		return costosTotalesCCPP(Categoria.SERVICES_CODE, simulado);
	}
	
	private Map <CentroCostos,Double> costosTotalesCCPPI(boolean simulado){
		return costosTotalesCCPP(Categoria.SIN_ASIGNAR_CODE, simulado);
	}
	
	private Map <CentroCostos,Double> costosTotalesCCPP(Integer categoria, boolean simulado){
		Map <CentroCostos,Double> costosTotalesCCPP = new HashMap<CentroCostos, Double>();
		
		List<Cuenta> cuentas = QueryUtil.getInstance().getCuentas();
		List<CentroCostos> paraProductivos = QueryUtil.getInstance().getCentroCostosByCategoria(categoria); 
		
		/*inicializo el mapa*/
		for(CentroCostos cc : paraProductivos){
			costosTotalesCCPP.put(cc, 0.0d);
		}
		
		for (Cuenta cu : cuentas){
			CuentaMes cum = QueryUtil.getInstance().getUltimaCuenta(cu);
			if (cum != null){	
				Double totalCuenta = simulado? cum.getCostoSimulado() : cum.getCosto();
				CriterioDistribucion c = cu.getCriterio();
			
				for(CentroCostos cc : paraProductivos){
					Double proporcion = getProporcion(c, cc);
					costosTotalesCCPP.put(cc, costosTotalesCCPP.get(cc) + totalCuenta*proporcion);
				}
			}	
		}
		return costosTotalesCCPP;
	}
	
	/*TODO: llevar a libreria o usar otro metodo*/
//	private Integer mesActual(){
//		Calendar cal = new GregorianCalendar();
//		Date fechaActual = new Date();
//		cal.setTime(fechaActual);
//		Integer mesActual = cal.get(Calendar.MONTH);
//		List<CuentaMes> cuentas = QueryUtil.getInstance().getCuentasByMes(mesActual);
//		if (cuentas == null || cuentas.isEmpty()){
//			if (mesActual != 0){
//				mesActual = mesActual -1;
//			}else{
//				mesActual = 11;
//			}
//		}
//		return mesActual;
//	}
	
	public List<Linea> getListaLineas() {
		if (lineaSelected == null){
			listaLineas = QueryUtil.getInstance().getLineas();
		}else{
			listaLineas = new ArrayList<Linea>();
			listaLineas.add(lineaSelected);
		}
		return listaLineas;
	}

	public void setListaLineas(List<Linea> listaLineas) {
		this.listaLineas = listaLineas;
	}
	
	public void valueChanged(ValueChangeEvent event) {
        if (null != event.getNewValue()) {
        	this.lineaSelected = (Linea)event.getNewValue(); 
        	listaLineas = new ArrayList<Linea>();
			listaLineas.add(lineaSelected);
        	FacesContext.getCurrentInstance().renderResponse();
        	try {
				FacesContext.getCurrentInstance().getExternalContext().redirect("calculo-costos.jsf");
			} catch (IOException e) {
				e.printStackTrace();
			}

        	
        }
    }
	
	private Double getCostoTipoMateriaPrima(TipoMateriaPrima tipo){
		Double costoUnitarioDolares = 0.00d;
		Double totalTipo  = QueryUtil.getInstance().getCostoPromedioByTipoMateria(tipo);
		if (totalTipo != null){
			costoUnitarioDolares = totalTipo /moneda.getCotizacion();
		}

		return costoUnitarioDolares;
	}

	public List<Linea> getLineasSeleccionadas() {
		return lineasSeleccionadas;
	}

	public void setLineasSeleccionadas(List<Linea> lineasSeleccionadas) {
		this.lineasSeleccionadas = lineasSeleccionadas;
	}

	public List<MateriaPrima> getPapeles() {
		return papeles;
	}

	public void setPapeles(List<MateriaPrima> papeles) {
		this.papeles = papeles;
	}	

}
